﻿using BenchmarkDotNet.Attributes;
using ExpressionBuilder.Common;
using ExpressionBuilder.Generics;
using ExpressionBuilder.Operations;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace BenchMarkTest.ExpressionBuilderTest
{
    public class Fifter_Auth
    {
        private readonly List<DbDate> _haystack = new List<DbDate>();
        private readonly int _haystackSize = 10000;
        private readonly int[] _ids = new[] { 1, 500, 5000, 9000 };
        private readonly DateTime? startDate = new DateTime(2022, 4, 1);
        private readonly DateTime? endDate = new DateTime(2023, 4, 1);
        public Fifter_Auth()
        {
            var date = DateTime.Now;
            Enumerable.Range(1, _haystackSize).ToList().ForEach(x => _haystack.Add(new DbDate()
            {
                Id = x,
                Date = date.AddHours(x)
            }));
        }

        //[Benchmark]
        //public List<DbDate> LinqByAuth()
        //{
        //    var query = _haystack.AsQueryable();
        //    var solution = query.Where(p => ((p.Date < startDate) || p.Date > endDate) ||
        //                                              (!_ids.Contains(p.Id) && (p.Date > startDate) && (p.Date < endDate))).ToList();
        //    var solution1 = query.Where(p => ((p.Date < startDate)) || (!_ids.Contains(p.Id) && (p.Date > startDate)));
        //    var solution2 = query.Where(p => (p.Date > endDate) || (!_ids.Contains(p.Id) && (p.Date < endDate)));
        //    return solution;
        //}

        [Benchmark]
        public List<DbDate> FifterByAuth()
        {
            var query = _haystack.AsQueryable();
            var result = QueryData(query, _ids, startDate, endDate).ToList();
            return result;
        }

        [Benchmark]
        public List<DbDate> LinqUnionByAuth()
        {
            var query = _haystack.AsQueryable();
            IQueryable<DbDate> queryPurchaseOrder = null;
            IQueryable<DbDate> queryPurchaseOrder1 = query;
            IQueryable<DbDate> queryPurchaseOrder2 = null;
            IQueryable<DbDate> queryPurchaseOrder3 = null;
            if (_ids != null && _ids.Length > 0)
            {
                queryPurchaseOrder = queryPurchaseOrder1.Where(s =>
                (!_ids.Contains(s.Id) & s.Date > startDate & s.Date < endDate)
                || s.Date < startDate || s.Date > endDate);
                queryPurchaseOrder1 = queryPurchaseOrder1.Where(s => !_ids.Contains(s.Id));
                if (startDate != null)
                {
                    queryPurchaseOrder1 = queryPurchaseOrder1.Where(s => s.Date > startDate);
                }
                if (endDate != null)
                {
                    queryPurchaseOrder1 = queryPurchaseOrder1.Where(s => s.Date < endDate);
                }
            }
            if (startDate != null)
            {
                queryPurchaseOrder2 = query.Where(s => s.Date < startDate);
            }

            if (endDate != null)
            {
                queryPurchaseOrder3 = query.Where(s => s.Date > endDate);
            }


            if (queryPurchaseOrder1 != null)
            {
                if (queryPurchaseOrder == null)
                {
                    queryPurchaseOrder = queryPurchaseOrder1;
                }
                else
                {
                    queryPurchaseOrder = queryPurchaseOrder.Union(queryPurchaseOrder1);
                }
            }


            if (queryPurchaseOrder2 != null)
            {
                if (queryPurchaseOrder == null)
                {
                    queryPurchaseOrder = queryPurchaseOrder2;
                }
                else
                {
                    queryPurchaseOrder = queryPurchaseOrder.Union(queryPurchaseOrder2);
                }
            }
            if (queryPurchaseOrder3 != null)
            {
                if (queryPurchaseOrder == null)
                {
                    queryPurchaseOrder = queryPurchaseOrder3;
                }
                else
                {
                    queryPurchaseOrder = queryPurchaseOrder.Union(queryPurchaseOrder3);
                }
            }
            if (queryPurchaseOrder != null)
            {
                query = queryPurchaseOrder;
            }
            return query.ToList();
        }


        public IQueryable<T> QueryData<T>(IQueryable<T> query, int[] ids, DateTime? startDate, DateTime? endDate)
        where T : class
        {
            var filter = new Filter<T>();
            filter.StartGroup();
            if (startDate != null)
                filter.By("Date", Operation.LessThan, startDate, Connector.Or);
            if (endDate != null)
                filter.By("Date", Operation.GreaterThan, endDate, Connector.Or);
            if (ids.Count() > 0)
            {
                filter.StartGroup();
                if (startDate == null && endDate == null)
                    filter.By("Id", Operation.NotIn, ids);
                else
                {
                    filter.By("Id", Operation.NotIn, ids.ToList(), Connector.And);
                    if (startDate != null && endDate != null)
                    {
                        filter.By("Date", Operation.GreaterThan, startDate, Connector.And);
                        filter.By("Date", Operation.LessThan, endDate);
                    }
                    if (startDate == null)
                        filter.By("Date", Operation.LessThan, endDate);
                    if (endDate == null)
                        filter.By("Date", Operation.GreaterThan, startDate);
                }
            }
            return query.Where(filter);
        }
    }
}
